﻿#region File and License Information
/*
<File>
	<License>
		Copyright © 2009 - 2017, Daniel Vaughan. All rights reserved.
		This file is part of Calcium (http://calciumsdk.net), 
		which is released under the MIT License.
		See file /Documentation/License.txt for details.
	</License>
	<CreationDate>2010-09-29 16:32:45Z</CreationDate>
</File>
*/
#endregion
//
//using System;
//using System.Collections;
//using System.Collections.Generic;
//using System.ComponentModel;
//using System.Diagnostics;
//using System.Linq;
//using System.Windows;
//using System.Windows.Threading;
//
//namespace Outcoder.ComponentModel.InputValidation
//{
//	public class DataErrorNotifier : INotifyDataErrorInfo
//	{
//		readonly IValidateData validator;
//		Dictionary<string, List<DataValidationError>> errorsField;
//
//		readonly object errorsLock = new object();
//
//		readonly IDictionary<string, Func<object>> propertyDictionary
//									= new Dictionary<string, Func<object>>();
//
//		readonly object propertyDictionaryLock = new object();
//
//		bool isEvaluating;
//		readonly object isEvaluatingLock = new object();
//		Action completeAction;
//		Action incompleteAction;
//		Action<Exception> unknownAction;
//		readonly object waitingForPropertiesLock = new object();
//
//		/// <summary>
//		/// Initializes a new instance 
//		/// of the <see cref="DataErrorNotifier"/> class.
//		/// </summary>
//		/// <param name="owner">The instance for which validation 
//		/// is being provided.</param>
//		/// <param name="validator">The validator.</param>
//		public DataErrorNotifier(
//			INotifyPropertyChanged owner, IValidateData validator)
//		{
//			this.validator = ArgumentValidator.AssertNotNull(
//													validator, "validator");
//			ArgumentValidator.AssertNotNull(owner, "owner");
//			validator.ValidationComplete += validator_ValidationComplete;
//			owner.PropertyChanged += OnOwnerPropertyChanged;
//		}
//
//		void OnOwnerPropertyChanged(object sender, PropertyChangedEventArgs e)
//		{
//			if (e == null || e.PropertyName == null)
//			{
//				return;
//			}
//			BeginGetPropertyErrorsFromValidator(e.PropertyName);
//		}
//
//		void BeginGetPropertyErrorsFromValidator(string propertyName)
//		{
//			Func<object> propertyFunc;
//			lock (propertyDictionaryLock)
//			{
//				if (!propertyDictionary.TryGetValue(propertyName, out propertyFunc))
//				{
//					/* No property registered with that name. */
//					return;
//				}
//			}
//			validator.BeginValidation(propertyName, propertyFunc());
//		}
//
//		readonly List<string> waitingForProperties = new List<string>();
//
//		void validator_ValidationComplete(
//			object sender, ValidationCompleteEventArgs e)
//		{
//			try
//			{
//				if (e.Exception == null)
//				{
//					SetPropertyErrors(e.PropertyName, e.Errors);
//				}
//			}
//			catch (Exception ex)
//			{
//				Debug.WriteLine("Unable to set property error." + ex);
//			}
//
//			if (isEvaluating)
//			{
//				lock (isEvaluatingLock)
//				{
//					if (isEvaluating)
//					{
//						try
//						{
//							bool finishedEvaluating;
//							lock (waitingForPropertiesLock)
//							{
//								waitingForProperties.Remove(e.PropertyName);
//								finishedEvaluating = waitingForProperties.Count < 1;
//							}
//
//							if (e.Exception != null)
//							{
//								isEvaluating = false;
//								if (unknownAction != null)
//								{
//									unknownAction(e.Exception);
//								}
//							}
//
//							if (e.Errors != null && e.Errors.Count() > 0)
//							{
//								isEvaluating = false;
//								if (incompleteAction != null)
//								{
//									incompleteAction();
//								}
//							}
//
//							if (finishedEvaluating)
//							{
//								bool success = isEvaluating;
//								isEvaluating = false;
//								if (success && completeAction != null)
//								{
//									completeAction();
//								}
//							}
//						}
//						catch (Exception ex)
//						{
//							Debug.WriteLine("Unable to validate property." + ex);
//							isEvaluating = false;
//						}
//					}
//				}
//			}
//		}
//
//		/// <summary>
//		/// Adds the property to the list of known class properties, 
//		/// which is used, for example, when performing validation 
//		/// of the whole class instance.
//		/// </summary>
//		/// <param name="name">The name of the property.</param>
//		/// <param name="property">The <c>Func</c> to 
//		/// retrieve the property.</param>
//		public void AddValidationProperty(string name, Func<object> property)
//		{
//			lock (propertyDictionaryLock)
//			{
//				propertyDictionary[name] = property;
//			}
//		}
//
//		public void IsComplete(Action completeAction,
//			Action incompleteAction, Action<Exception> unknownAction)
//		{
//			this.completeAction = completeAction;
//			this.incompleteAction = incompleteAction;
//			this.unknownAction = unknownAction;
//
//			try
//			{
//				if (!LockedOperations.TrySetTrue(
//					ref isEvaluating, isEvaluatingLock))
//				{
//					return;
//				}
//
//				if (propertyDictionary == null)
//				{
//					if (completeAction != null)
//					{
//						completeAction();
//					}
//					return;
//				}
//
//				lock (waitingForPropertiesLock)
//				{
//					waitingForProperties.Clear();
//					foreach (KeyValuePair<string, Func<object>> pair
//						in propertyDictionary)
//					{
//						waitingForProperties.Add(pair.Key);
//					}
//				}
//				foreach (KeyValuePair<string, Func<object>> pair in propertyDictionary)
//				{
//					validator.BeginValidation(pair.Key, pair.Value());
//				}
//			}
//			catch (Exception ex)
//			{
//				isEvaluating = false;
//				if (unknownAction != null)
//				{
//					unknownAction(ex);
//				}
//			}
//		}
//
//		/// <summary>
//		/// Gets the validation errors for all properties.
//		/// </summary>
//		/// <value>The errors.</value>
//		Dictionary<string, List<DataValidationError>> Errors
//		{
//			get
//			{
//				/* Lazy loaded. */
//				if (errorsField == null)
//				{
//					lock (errorsLock)
//					{
//						if (errorsField == null)
//						{
//							errorsField = new Dictionary<string,
//													List<DataValidationError>>();
//						}
//					}
//				}
//				return errorsField;
//			}
//		}
//
//		public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
//
//		/// <summary>
//		/// Gets the validation errors for a specified property 
//		/// or for the entire object.
//		/// </summary>
//		/// <param name="propertyName">The name of the property 
//		/// to retrieve validation errors for, 
//		/// or null or <see cref="F:System.String.Empty"/> 
//		/// to retrieve errors for the entire object.</param>
//		/// <returns>
//		/// The validation errors for the property or object.
//		/// </returns>
//		public IEnumerable GetErrors(string propertyName)
//		{
//			return GetDataValidationErrors(propertyName);
//		}
//
//		/// <summary>
//		/// Gets the validation errors for a specified property 
//		/// or for the entire object.
//		/// </summary>
//		/// <param name="propertyName">The name of the property 
//		/// to retrieve validation errors for, 
//		/// or null or <see cref="F:System.String.Empty"/> 
//		/// to retrieve errors for the entire object.</param>
//		/// <returns>
//		/// The validation errors for the property or object.
//		/// </returns>
//		public IEnumerable<DataValidationError> GetDataValidationErrors(
//			string propertyName)
//		{
//			if (string.IsNullOrEmpty(propertyName))
//			{
//				lock (errorsLock)
//				{
//					if (errorsField == null)
//					{
//						return new List<DataValidationError>();
//					}
//
//					var result = from list in errorsField.Values
//								 from errorInfo in list
//								 select errorInfo;
//					return result;
//				}
//			}
//
//			lock (errorsLock)
//			{
//				List<DataValidationError> propertyErrors;
//				if (errorsField == null
//					|| !errorsField.TryGetValue(propertyName, out propertyErrors))
//				{
//					return new List<DataValidationError>();
//				}
//				return propertyErrors.ToList();
//			}
//		}
//
//		/// <summary>
//		/// Raises the <see cref="ErrorsChanged"/> event.
//		/// </summary>
//		/// <param name="property">The property 
//		/// for which the list of errors changed.</param>
//		protected virtual void OnErrorsChanged(string property)
//		{
//			Dispatcher dispatcher = Deployment.Current.Dispatcher;
//			dispatcher.InvokeIfRequired(
//				delegate
//				{
//					ErrorsChanged?.Invoke(this,
//						new DataErrorsChangedEventArgs(property));
//				});
//		}
//
//		/// <summary>
//		/// Raises the ErrorsChanged event.
//		/// </summary>
//		public void RaiseErrorsChanged()
//		{
//			OnErrorsChanged(string.Empty);
//		}
//
//		/// <summary>
//		/// Gets a value that indicates whether the object has validation errors.
//		/// </summary>
//		/// <value></value>
//		/// <returns><c>true</c> if the object currently has validation errors; 
//		/// otherwise, <c>false</c>.</returns>
//		public bool HasErrors
//		{
//			get
//			{
//				lock (errorsLock)
//				{
//					return errorsField != null && Errors.Count > 0;
//				}
//			}
//		}
//
//		/// <summary>
//		/// Removes the property error from the properties list 
//		/// of validation errors.
//		/// </summary>
//		/// <param name="propertyName">Name of the property.</param>
//		/// <param name="errorCode">The error code.</param>
//		public void RemovePropertyError(string propertyName, int errorCode)
//		{
//			bool raiseEvent = false;
//
//			lock (errorsLock)
//			{
//				if (errorsField == null)
//				{
//					return;
//				}
//
//				List<DataValidationError> list = errorsField[propertyName];
//				DataValidationError dataValidationError
//					= list.SingleOrDefault(e => e.Id == errorCode);
//
//				if (dataValidationError != null)
//				{
//					list.Remove(dataValidationError);
//					raiseEvent = true;
//				}
//			}
//
//			if (raiseEvent)
//			{
//				OnErrorsChanged(propertyName);
//			}
//		}
//
//		/// <summary>
//		/// Adds a property error for the specified propertyName.
//		/// This may produce a prompt in the UI to correct the error before proceeding.
//		/// </summary>
//		/// <param name="propertyName">Name of the property.</param>
//		/// <param name="dataValidationError">The data validation error.</param>
//		public void AddPropertyError(
//			string propertyName, DataValidationError dataValidationError)
//		{
//			SetPropertyErrors(propertyName,
//				new List<DataValidationError> { dataValidationError });
//		}
//
//		/// <summary>
//		/// Sets the known validation errors for a property.
//		/// This may produce a prompt in the UI to correct the error before proceeding.
//		/// </summary>
//		/// <param name="propertyName">Name of the property.</param>
//		/// <param name="dataErrors">The data errors.</param>
//		public void SetPropertyErrors(
//			string propertyName, IEnumerable<DataValidationError> dataErrors)
//		{
//			ArgumentValidator.AssertNotNullOrEmpty(propertyName, "propertyName");
//
//			List<DataValidationError> list;
//			bool raiseEvent = false;
//			lock (errorsLock)
//			{
//				bool created = false;
//
//				int paramErrorCount = dataErrors == null ? 0 : dataErrors.Count();
//				if ((errorsField == null || errorsField.Count < 1)
//					&& paramErrorCount < 1)
//				{
//					return;
//				}
//
//				if (errorsField == null)
//				{
//					errorsField
//						= new Dictionary<string, List<DataValidationError>>();
//					created = true;
//				}
//
//				bool listFound = false;
//				if (created ||
//					!(listFound = errorsField.TryGetValue(propertyName, out list)))
//				{
//					list = new List<DataValidationError>();
//				}
//
//				if (paramErrorCount < 1)
//				{
//					if (listFound)
//					{
//						errorsField.Remove(propertyName);
//						raiseEvent = true;
//					}
//				}
//				else
//				{
//					var tempList = new List<DataValidationError>();
//					foreach (var dataError in dataErrors)
//					{
//						if (created || list.SingleOrDefault(
//							e => e.Id == dataError.Id) == null)
//						{
//							tempList.Add(dataError);
//							raiseEvent = true;
//						}
//					}
//					list.AddRange(tempList);
//					errorsField[propertyName] = list;
//				}
//			}
//
//			if (raiseEvent)
//			{
//				OnErrorsChanged(propertyName);
//			}
//		}
//	}
//}
//
